package client
import (
"github.com/jcmturner/gokrb5/v8/iana/flags"
"github.com/jcmturner/gokrb5/v8/iana/nametype"
"github.com/jcmturner/gokrb5/v8/krberror"
"github.com/jcmturner/gokrb5/v8/messages"
"github.com/jcmturner/gokrb5/v8/types"
)
func (cl *Client ) TGSREQGenerateAndExchange (spn types .PrincipalName , kdcRealm string , tgt messages .Ticket , sessionKey types .EncryptionKey , renewal bool ) (tgsReq messages .TGSReq , tgsRep messages .TGSRep , err error ) {
tgsReq , err = messages .NewTGSReq (cl .Credentials .CName (), kdcRealm , cl .Config , tgt , sessionKey , spn , renewal )
if err != nil {
return tgsReq , tgsRep , krberror .Errorf (err , krberror .KRBMsgError , "TGS Exchange Error: failed to generate a new TGS_REQ" )
}
return cl .TGSExchange (tgsReq , kdcRealm , tgsRep .Ticket , sessionKey , 0 )
}
func (cl *Client ) TGSExchange (tgsReq messages .TGSReq , kdcRealm string , tgt messages .Ticket , sessionKey types .EncryptionKey , referral int ) (messages .TGSReq , messages .TGSRep , error ) {
var tgsRep messages .TGSRep
b , err := tgsReq .Marshal ()
if err != nil {
return tgsReq , tgsRep , krberror .Errorf (err , krberror .EncodingError , "TGS Exchange Error: failed to marshal TGS_REQ" )
}
r , err := cl .sendToKDC (b , kdcRealm )
if err != nil {
if _ , ok := err .(messages .KRBError ); ok {
return tgsReq , tgsRep , krberror .Errorf (err , krberror .KDCError , "TGS Exchange Error: kerberos error response from KDC when requesting for %s" , tgsReq .ReqBody .SName .PrincipalNameString ())
}
return tgsReq , tgsRep , krberror .Errorf (err , krberror .NetworkingError , "TGS Exchange Error: issue sending TGS_REQ to KDC" )
}
err = tgsRep .Unmarshal (r )
if err != nil {
return tgsReq , tgsRep , krberror .Errorf (err , krberror .EncodingError , "TGS Exchange Error: failed to process the TGS_REP" )
}
err = tgsRep .DecryptEncPart (sessionKey )
if err != nil {
return tgsReq , tgsRep , krberror .Errorf (err , krberror .EncodingError , "TGS Exchange Error: failed to process the TGS_REP" )
}
if ok , err := tgsRep .Verify (cl .Config , tgsReq ); !ok {
return tgsReq , tgsRep , krberror .Errorf (err , krberror .EncodingError , "TGS Exchange Error: TGS_REP is not valid" )
}
if tgsRep .Ticket .SName .NameString [0 ] == "krbtgt" && !tgsRep .Ticket .SName .Equal (tgsReq .ReqBody .SName ) {
if referral > 5 {
return tgsReq , tgsRep , krberror .Errorf (err , krberror .KRBMsgError , "TGS Exchange Error: maximum number of referrals exceeded" )
}
cl .addSession (tgsRep .Ticket , tgsRep .DecryptedEncPart )
realm := tgsRep .Ticket .SName .NameString [len (tgsRep .Ticket .SName .NameString )-1 ]
referral ++
if types .IsFlagSet (&tgsReq .ReqBody .KDCOptions , flags .EncTktInSkey ) && len (tgsReq .ReqBody .AdditionalTickets ) > 0 {
tgsReq , err = messages .NewUser2UserTGSReq (cl .Credentials .CName (), kdcRealm , cl .Config , tgt , sessionKey , tgsReq .ReqBody .SName , tgsReq .Renewal , tgsReq .ReqBody .AdditionalTickets [0 ])
if err != nil {
return tgsReq , tgsRep , err
}
}
tgsReq , err = messages .NewTGSReq (cl .Credentials .CName (), realm , cl .Config , tgsRep .Ticket , tgsRep .DecryptedEncPart .Key , tgsReq .ReqBody .SName , tgsReq .Renewal )
if err != nil {
return tgsReq , tgsRep , err
}
return cl .TGSExchange (tgsReq , realm , tgsRep .Ticket , tgsRep .DecryptedEncPart .Key , referral )
}
cl .cache .addEntry (
tgsRep .Ticket ,
tgsRep .DecryptedEncPart .AuthTime ,
tgsRep .DecryptedEncPart .StartTime ,
tgsRep .DecryptedEncPart .EndTime ,
tgsRep .DecryptedEncPart .RenewTill ,
tgsRep .DecryptedEncPart .Key ,
)
cl .Log ("ticket added to cache for %s (EndTime: %v)" , tgsRep .Ticket .SName .PrincipalNameString (), tgsRep .DecryptedEncPart .EndTime )
return tgsReq , tgsRep , err
}
func (cl *Client ) GetServiceTicket (spn string ) (messages .Ticket , types .EncryptionKey , error ) {
var tkt messages .Ticket
var skey types .EncryptionKey
if tkt , skey , ok := cl .GetCachedTicket (spn ); ok {
return tkt , skey , nil
}
princ := types .NewPrincipalName (nametype .KRB_NT_PRINCIPAL , spn )
realm := cl .spnRealm (princ )
if realm == "" {
realm = cl .Credentials .Realm ()
}
tgt , skey , err := cl .sessionTGT (realm )
if err != nil {
return tkt , skey , err
}
_ , tgsRep , err := cl .TGSREQGenerateAndExchange (princ , realm , tgt , skey , false )
if err != nil {
return tkt , skey , err
}
return tgsRep .Ticket , tgsRep .DecryptedEncPart .Key , nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .